package sensors;

import flixel.FlxObject;
import flixel.FlxSprite;
import flixel.addons.tile.FlxTilemapExt;
import flixel.group.FlxGroup;
import level.Tiles;
import flixel.util.FlxPoint;

class BasicSensor extends FlxObject
{
 	private static var _sensors: Map<String, FlxGroup> = new Map<String, FlxGroup>(); // grupo de sensores segun su tipo, todos deberían agregarse (el add se debería hacer en las clases derivadas)
 	public var isActive(default, null): Bool;	// si está o no activado
 	public var id(default, null): Int;			// id del sensor
 	private var _map: FlxTilemapExt; 			// tilemap donde se dibujan los sensores
 	private var _posi: Int;						// posición en x del sensor (en tiles)
 	private var _posj: Int;						// posición en y del sensor (en tiles)
 	private var _iTile: Int;					// indice del tile
 	private var _path: Array<Int>;				// el path de cable hasta el proximo sensor
 	
 	public function new(X: Float, Y: Float, map: FlxTilemapExt){
 		super(X, Y);
 		isActive = false;
 		_map = map;
 		var tileWidth: Float = _map.width / _map.widthInTiles;
 		var tileHeight: Float = _map.height / _map.heightInTiles;
 		_iTile = Std.int(x/tileWidth) + Std.int(y/tileHeight)*_map.widthInTiles;
 		deactivate();
 	}

 	public function activate(): Void
 	{
 		if (!isActive && _path != null)
		{
			for(i in 0..._path.length)
			{
				var tile = _map.getTileByIndex(_path[i]);
				_map.setTileByIndex(_path[i], tile + 5, true);
			}
		}
		isActive = true;
 	}
 	
 	public function deactivate(): Void
 	{
 		if (isActive && _path != null)
		{
			for(i in 0..._path.length)
			{
				var tile = _map.getTileByIndex(_path[i]);
				_map.setTileByIndex(_path[i], tile - 5, true);
			}
		}
		isActive = false;
 	}

 	private function drawTile(tile: Int): Void
 	{
 		_map.setTile(_posi, _posj, tile, true);
 	}

 	// inicializa el mapa con grupos de sensores
 	public static function initAll()
 	{
 		_sensors.set("TouchSensor", new FlxGroup());
 		_sensors.set("AndSensor", new FlxGroup());
 		_sensors.set("DoorSensor", new FlxGroup());
 	}

 	public static function getSensors(SensorType: String): FlxGroup
 	{
 		return _sensors[SensorType];
 	}

 	public function bind()
 	{
 		trace("binding sensor: "+_iTile);
 		_path = new Array<Int>();
 		
 		// el sensor solo debe salir para un lado, buscamos cual es ese lado
 		// si sale por arriba
 		if(tileComesFromDown(_map.getTileByIndex(_iTile - _map.widthInTiles)))
 		{
 			trace("true");
 			followPath(_iTile - _map.widthInTiles);
 		}
 		// si sale por abajo
 		else if(tileComesFromUp(_map.getTileByIndex(_iTile + _map.widthInTiles)))
 		{
 			trace("true");
 			followPath(_iTile + _map.widthInTiles);
 		}
 		// si sale por derecha
 		else if(tileComesFromLeft(_map.getTileByIndex(_iTile + 1)))
 		{
 			trace("true");
 			followPath(_iTile + 1);
 		}
 		// si sale por izquierda
 		else if(tileComesFromRight(_map.getTileByIndex(_iTile - 1)))
 		{
 			trace("true");
 			followPath(_iTile - 1);
 		}
 		// puede ser que el sensor no salga por ningun lado...
 	}

 	private function followPath(currentTileIndex: Int)
 	{
 		var currentTile = _map.getTileByIndex(currentTileIndex);
 		
 		if(!tileIsWire(currentTile))
 		{
 			// el tile es un sensor, lo registramos como dependiente nuestro
 			var child: DependentSensor = DependentSensor.getSensorByTileIndex(currentTileIndex);
 			child.registerParentSensor(this);
 			trace("Registering sensor "+_iTile+" as parent of "+currentTileIndex);
 		}
 		else
 		{
 			// agregamos el currentTile al path
 			_path.push(currentTileIndex);

			// busca el tile siguiente en base al valor del actual
 			var nextTileIndex: Int;
 			if(tileGoesUp(currentTile))
 			{
				nextTileIndex = currentTileIndex - _map.widthInTiles;
 			}
 			else if(tileGoesDown(currentTile))
 			{
 				nextTileIndex = currentTileIndex + _map.widthInTiles; 
 			}
 			else if(tileGoesLeft(currentTile))
 			{
 				nextTileIndex = currentTileIndex - 1;
 			}
 			else
 			{
 				nextTileIndex = currentTileIndex + 1;
 			}
 			followPath(nextTileIndex);
 		}
 	}

 	private function tileIsWire(tile: Int): Bool
 	{
	 	if(Tiles.WIRE_L2R.indexOf(tile) != -1)
	 	 	return true;

		if(Tiles.WIRE_R2L.indexOf(tile) != -1)
	 	 	return true;

		if(Tiles.WIRE_U2D.indexOf(tile) != -1)
	 	 	return true;

		if(Tiles.WIRE_D2U.indexOf(tile) != -1)
	 	 	return true;

		if(Tiles.WIRE_L2U.indexOf(tile) != -1)
	 	 	return true;

		if(Tiles.WIRE_L2D.indexOf(tile) != -1)
	 	 	return true;

		if(Tiles.WIRE_R2U.indexOf(tile) != -1)
	 	 	return true;

		if(Tiles.WIRE_R2D.indexOf(tile) != -1)
	 	 	return true;

		if(Tiles.WIRE_U2L.indexOf(tile) != -1)
	 	 	return true;
		
		if(Tiles.WIRE_U2R.indexOf(tile) != -1)
	 	 	return true;
		
		if(Tiles.WIRE_D2L.indexOf(tile) != -1)
	 	 	return true;

		if(Tiles.WIRE_D2R.indexOf(tile) != -1)
	 	 	return true;

		return false;
	}

	private function tileComesFromLeft(tile: Int): Bool
	{
		return Tiles.WIRE_L2R.indexOf(tile) != -1 || Tiles.WIRE_L2U.indexOf(tile) != -1 || Tiles.WIRE_L2D.indexOf(tile) != -1;
	}
	
	private function tileComesFromRight(tile: Int): Bool
	{
		return Tiles.WIRE_R2L.indexOf(tile) != -1 || Tiles.WIRE_R2U.indexOf(tile) != -1 || Tiles.WIRE_R2D.indexOf(tile) != -1;
	}
	
	private function tileComesFromUp(tile: Int): Bool
	{
		if(Tiles.WIRE_U2D.indexOf(tile) != -1)
	 	 	return true;
	 	if(Tiles.WIRE_U2L.indexOf(tile) != -1)
	 	 	return true;
	 	if(Tiles.WIRE_U2R.indexOf(tile) != -1)
	 	 	return true;
	 	return false;
	}
	
	private function tileComesFromDown(tile: Int): Bool
	{
		if(Tiles.WIRE_D2U.indexOf(tile) != -1)
	 	 	return true;
	 	if(Tiles.WIRE_D2L.indexOf(tile) != -1)
	 	 	return true;
	 	if(Tiles.WIRE_D2R.indexOf(tile) != -1)
	 	 	return true;
	 	return false;
	}

	private function tileGoesLeft(tile: Int): Bool
	{
		if(Tiles.WIRE_R2L.indexOf(tile) != -1)
	 	 	return true;
	 	if(Tiles.WIRE_U2L.indexOf(tile) != -1)
	 	 	return true;
	 	if(Tiles.WIRE_D2L.indexOf(tile) != -1)
	 	 	return true;
	 	return false;
	}
	
	private function tileGoesRight(tile: Int): Bool
	{
		if(Tiles.WIRE_L2R.indexOf(tile) != -1)
	 	 	return true;
	 	if(Tiles.WIRE_D2R.indexOf(tile) != -1)
	 	 	return true;
	 	if(Tiles.WIRE_U2R.indexOf(tile) != -1)
	 	 	return true;
	 	return false;
	}
	
	private function tileGoesUp(tile: Int): Bool
	{
		if(Tiles.WIRE_D2U.indexOf(tile) != -1)
	 	 	return true;
	 	if(Tiles.WIRE_L2U.indexOf(tile) != -1)
	 	 	return true;
	 	if(Tiles.WIRE_R2U.indexOf(tile) != -1)
	 	 	return true;
	 	return false;
	}
	
	private function tileGoesDown(tile: Int): Bool
	{
		if(Tiles.WIRE_U2D.indexOf(tile) != -1)
	 	 	return true;
	 	if(Tiles.WIRE_R2D.indexOf(tile) != -1)
	 	 	return true;
	 	if(Tiles.WIRE_L2D.indexOf(tile) != -1)
	 	 	return true;
	 	return false;
	}

	// inicializa el mapa con grupos de sensores
 	public static function bindAll()
 	{
 		for(group in _sensors.iterator())
 		{
 			for(a in group)
 			{
 				cast(a, sensors.BasicSensor).bind();
 			}
 		}
 	}

} 